/**
 * 
 */
package qy.jalgotrade.broker;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import qy.jalgotrade.event.Dispatcher;
import qy.jalgotrade.event.Event;
import qy.jalgotrade.event.Subject;

/**
 * <pre>
 * Base class for brokers.
 * 
 * .. note::
 * 
 *     This is a base class and should not be used directly.
 * </pre>
 * 
 * @author c-geo
 *
 */
public abstract class Broker extends Subject {

	private Event __orderEvent;

	public Broker() {

		super();
		__orderEvent = new Event("broker-order-event");
		setDispatchPriority(Dispatcher.DispatcherPrio.BROKER);
	}

	public void notifyOrderEvent(OrderEvent orderEvent) {

		Map<String, Object> params = new HashMap<>();
		params.put("broker", this);
		params.put("orderEvent", orderEvent);

		__orderEvent.emit(__orderEvent.getName(), params);
	}

	/**
	 * <pre>
	 * Handlers should expect 2 parameters:
	 * 1: broker instance
	 * 2: OrderEvent instance
	 * </pre>
	 * 
	 * @return
	 */
	public Event getOrderUpdatedEvent() {

		return __orderEvent;
	}

	public abstract InstrumentTraits getInstrumentTraits(String instrument);

	/**
	 * Returns the available cash.
	 * 
	 * @return
	 */
	public double getCash() {

		return getCash(true);
	}

	/**
	 * Returns the available cash.
	 * 
	 * @param includeShort Include cash from short positions.
	 * @return
	 */
	public abstract double getCash(boolean includeShort);

	/**
	 * Returns the portfolio value (cash + shares * price).
	 * 
	 * @return
	 */
	public abstract double getEquity();

	/**
	 * Returns the number of shares for an instrument.
	 * 
	 * @param instrument
	 * @return
	 */
	public abstract double getShares(String instrument);

	/**
	 * Returns a dictionary that maps instruments to shares.
	 * 
	 * @return
	 */
	public abstract Map<String, Double> getPositions();

	/**
	 * Returns a sequence with the orders that are still active.
	 * 
	 * @return
	 */
	public List<Order> getActiveOrders() {

		return getActiveOrders(null);
	}

	/**
	 * Returns a sequence with the orders that are still active.
	 * 
	 * @param instrument An optional instrument identifier to return only the active orders for the
	 *                   given instrument.
	 * @return
	 */
	public abstract List<Order> getActiveOrders(String instrument);

	/**
	 * <pre>
	 * Submits an order.
	 * 
	 * .. note::
	 *     * After this call the order is in SUBMITTED state and an event is not triggered for this transition.
	 *     * Calling this twice on the same order will raise an exception.
	 * </pre>
	 * 
	 * @param order The order to submit.
	 * @throws Exception
	 */
	public abstract void submitOrder(Order order) throws Exception;

	/**
	 * Creates a Market order. A market order is an order to buy or sell a stock at the best available
	 * price. Generally, this type of order will be executed immediately. However, the price at which a
	 * market order will be executed is not guaranteed.
	 * 
	 * @param action     The order action.
	 * @param instrument Instrument identifier.
	 * @param quantity   Order quantity.
	 * @return
	 * @throws Exception
	 */
	public MarketOrder createMarketOrder(Order.Action action, String instrument, double quantity) throws Exception {

		return createMarketOrder(action, instrument, quantity, false);
	}

	/**
	 * Creates a Market order. A market order is an order to buy or sell a stock at the best available
	 * price. Generally, this type of order will be executed immediately. However, the price at which a
	 * market order will be executed is not guaranteed.
	 * 
	 * @param action     The order action.
	 * @param instrument Instrument identifier.
	 * @param quantity   Order quantity.
	 * @param onClose    True if the order should be filled as close to the closing price as possible
	 *                   (Market-On-Close order). Default is False.
	 * @return
	 * @throws Exception
	 */
	public abstract MarketOrder createMarketOrder(Order.Action action, String instrument, double quantity,
	        boolean onClose) throws Exception;

	/**
	 * Creates a Limit order. A limit order is an order to buy or sell a stock at a specific price or
	 * better. A buy limit order can only be executed at the limit price or lower, and a sell limit
	 * order can only be executed at the limit price or higher.
	 * 
	 * @param action     The order action.
	 * @param instrument Instrument identifier.
	 * @param limitPrice The order price.
	 * @param quantity   Order quantity.
	 * @return
	 * @throws Exception
	 */
	public abstract LimitOrder createLimitOrder(Order.Action action, String instrument, double limitPrice,
	        double quantity) throws Exception;

	/**
	 * Creates a Stop order.<br />
	 * A stop order, also referred to as a stop-loss order, is an order to buy or sell a stock once the
	 * price of the stock reaches a specified price, known as the stop price.<br />
	 * When the stop price is reached, a stop order becomes a market order.<br />
	 * A buy stop order is entered at a stop price above the current market price.<br />
	 * Investors generally use a buy stop order to limit a loss or to protect a profit on a stock that
	 * they have sold short. <br />
	 * A sell stop order is entered at a stop price below the current market price. <br />
	 * Investors generally use a sell stop order to limit a loss or to protect a profit on a stock that
	 * they own.
	 * 
	 * @param action     The order action.
	 * @param instrument Instrument identifier.
	 * @param stopPrice  The trigger price.
	 * @param quantity   Order quantity.
	 * @return
	 * @throws Exception
	 */
	public abstract StopOrder createStopOrder(Order.Action action, String instrument, double stopPrice, double quantity)
	        throws Exception;

	/**
	 * Creates a Stop-Limit order.<br />
	 * A stop-limit order is an order to buy or sell a stock that combines the features of a stop order
	 * and a limit order.<br />
	 * Once the stop price is reached, a stop-limit order becomes a limit order that will be executed at
	 * a specified price (or better). The benefit of a stop-limit order is that the investor can control
	 * the price at which the order can be executed.
	 * 
	 * @param action     The order action.
	 * @param instrument Instrument identifier.
	 * @param stopPrice  The trigger price.
	 * @param limitPrice he price for the limit order.
	 * @param quantity   Order quantity.
	 * @return
	 * @throws Exception
	 */
	public abstract StopLimitOrder createStopLimitOrder(Order.Action action, String instrument, double stopPrice,
	        double limitPrice, double quantity) throws Exception;

	/**
	 * Requests an order to be canceled. If the order is filled an Exception is raised.
	 * 
	 * @param order The order to cancel.
	 * @throws Exception
	 */
	public abstract void cancelOrder(Order order) throws Exception;
}
